/*
 * 基础封装 Ajax 、HashTable、BaseControl、String扩展
 * @Author: kevin.huang
 * @Date: 2018-07-21 09:09:53 
 * @Last Modified by: kevin.huang
 * @Last Modified time: 2019-05-07 20:42:25
 * Copyright (c): kevin.huang Released under MIT License
 */
/**
 * 2019-07-20 解决destroy 相互引用存在的死循环调用问题
 * 2019-07-19 panel组件关闭监听，新增处理关闭前销毁/关闭时间日期，下拉列表的弹窗，完善destroy销毁逻辑,
 * 优化所有组件里面注册到window，body上的事件销毁处理,优化combox下来高度计算
 * 2019-05-16新增jsonViewer
 * 2019-05-14支持window选择输入框
 * 2019-05-12 新增动态表单支持 dyForm
 * 2019-05-03 bindForm 支持calendar时间日期控件
 * ***/
(function (global, factory) {
    if (typeof define === 'function' && define.amd && !window["_all_in_"]) {
        define(['jquery', 'config'], function ($, c) {
            return factory(global, $, c);
        });
    } else {
        factory(global, $);
    }
}(typeof window !== "undefined" ? window : this, function (window, $, cfg) {
    "use strict";
    var $B = window["$B"] ? window["$B"] : {};
    window["$B"] = $B;
    var config = $B.config;
    var document = window.document;
    var charSpan = "<span style='position:absolute;white-space:nowrap;top:-10000000px;left:-10000000px' id='{id}'></span>",
        $body,
        _char_id_ = "__getcharwidth__",
        _ellipsis_char_id = "_ellipsis_char_",
        $spen_CharWidth,
        $ellipsisCharDiv = null,
        loadingHtml = "<div style='padding-left:16px;' class='loading'>" + config.loading + "</div>",
        chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    
    var srcollArray = [];    
    var SCROLLCHECKER ;    

    /**定义一个BaseControl,封装一些共有方法***/
    function BaseControl() {
        this._version = '_ver_var_';
        this._release = '_ver_date_';
        this._author = '_ver_site_';
    }
    BaseControl.prototype = {
        constructor: BaseControl,
        version: function () {
            $B.debug(this._version);
            $B.debug(this._release);
            $B.debug(this._author);
        },
        /*** ajax请求
         args={
                async: true,
                url:'',
                data:{},
                ok:function(data,message){},
                fail:function(message){},
                final:function(res){}
        }
        ***/
        ajax: function (args) {
            $B.request(args);
        },
        debug: function (msg) {
            $B.debug(msg);
        },
        error: function (err) {
            $B.debug("error:" + err);
        },
        clear: function () {
            if (this.jqObj) {
                this.jqObj.children().remove();
            }
            this.delProps();
        },
        /**
         * 注册一个函数
         * **/
        regiterFn: function (fnName, fn) {
            this[fnName] = fn;
        },
        /***
         * excuObjName 解决相互引用的 destroy被死循环调用的情况
         * ****/
        destroy: function (excuObjName) {
            if (this.jqObj) {
                this.jqObj.remove();
            }
            this.delProps(excuObjName);
            /***清空继承链***/
            this["__proto__"] = {};
        },
        /***解除所有私有引用***/
        delProps: function (excuObjName) {
            for (var p in this) {
                if (this.hasOwnProperty(p)) {                    
                    if(this[p] !== null && this[p] !== undefined){
                        if( p !== "super" && typeof(this[p].destroy) === "function"){
                            if(!excuObjName || excuObjName !== this[p]){
                                this[p].destroy(this);
                            }
                        }
                    }                    
                    delete this[p];
                }
            }
        }
    };
    function _getBody() {
        if (!$body) {
            $body = $(document.body).css("position", "relative");
        }
        return $body;
    }
    var removeClearTimer;
    var TextEvents = {
        input: function () {
            var $t = $(this);
            if ($t.val() !== "") {
                var $b = _getBody();
                var btn = $b.children("#k_text_clear_btn");
                if (btn.length === 0 || btn.data("target") !== this) {
                    TextEvents.mouseover.call(this);
                }
            }
        },
        mouseover: function () {
            clearTimeout(removeClearTimer);
            var $t = $(this);
            if (!$t.attr("readonly")) {
                var $b = _getBody();
                var clrBtn = $b.children("#k_text_clear_btn").hide();
                if ($t.val() !== "") {
                    var ofs = $t.offset();
                    var left = $t.outerWidth() + ofs.left - 15;
                    var top = ($t.outerHeight() / 2) + ofs.top - 12;
                    if ($t.hasClass("k_combox_input")) {
                        left = left - 18;
                    }
                    if (clrBtn.length === 0) {
                        clrBtn = $("<div id='k_text_clear_btn' style='cursor:pointer;position:absolute;top:" + top + "px;left:" + left + "px;width:14px;height:14px;z-index:2147483647;'><i style='color:#C1C1C1' class='fa fa-cancel-2'></i></div>");
                        clrBtn.appendTo($b).on({
                            click: function () {
                                var $input = $(this).data("target");
                                $input.val("");
                                $input.trigger("input.mvvm");
                                $(this).hide();
                                $input.focus();
                            }
                        }).data("target", $t);
                    } else {
                        clrBtn.data("target", $t).css({ top: top, left: left }).show();
                    }
                }
            }
        },
        mouseout: function (e) {
            var $b = _getBody();
            removeClearTimer = setTimeout(function () {
                $b.children("#k_text_clear_btn").hide();
            }, 800);
        }
    };
    var ajaxOpts = {
        waiting: false,
        timeout: 2000 * 60,
        type: "POST",
        dataType: 'json',
        async: true,
        error: function (xhr, status, errorThrown) {
            this.removeWaiting();
            this.recoverButton();
            var res = {
                message: config.permission + xhr.status
            };
            if (window.console) {
                console.log(xhr.responseText);
            }
            try {
                res = eval('(' + xhr.responseText + ')');
            } catch (e) {
            }
            if (xhr.status === 200) {
                this.success(res);
            } else {
                if (_getBody().children("._request_error_window").length === 0) {
                    var win =  $B.error(config.requestError);
                     win.jqObj.addClass("_request_error_window");
                }
            }           
            this.final(status);
        },
        success: function (res) {           
            this.removeWaiting();
            this.recoverButton();
            this.final(res);
            if (typeof res.code !== "undefined") {
                if (res.code === 0) {
                    var data = res.data;
                    if (res.strConvert) {
                        data = eval('(' + res.data + ')');
                    }
                    this.ok(res.message, data, res);
                } else if (res.code === 99999) {
                    if (res.data === "notlogin") {
                        $B.error(res.message);
                        setTimeout(function () {
                            if (window.ctxPath) {
                                window.top.location = $B.getHttpHost(window.ctxPath);
                            }
                        }, 1600);
                    } else {
                        $B.error(config.permission);
                    }
                } else {
                    this.fail(res.message, res);
                }
            } else {
                this.ok(res, res);
            }
        },
        /**
         *当返回结果是正确时的处理
         *data:返回的数据
         *message:提示的信息
         **/
        ok: function (message, data) { },
        recoverButton: function () {
            if (this["target"]) {
                this["target"].removeAttr("disabled");
                if (this["target"][0].tagName === "INPUT") {
                    this["target"].val(this.recoverText);
                } else {
                    this["target"].html(this.recoverText);
                }
                this["target"] = undefined;
            }
        },
        removeWaiting:function(){
            if(this.waiting){      
                this.waiting = undefined;        
                this.waitingObj.close();
                this.waitingObj = undefined;
            }
        },
        /***
         *当返回结果是非正确时的处理
         ***/
        fail: function (msg, res) {
            if (_getBody().children("._request_fail_window_").length === 0) {
                var win = $B.alert(msg);
                win.jqObj.addClass("_request_fail_window_");
            }
        },
        /**
         * 无论如何都回调的函数
         ****/
        final: function (res) { //无论成功，失败，错误都执行的回调
        }
    };
    /****原生扩展******/
    //-------------------------------------
    //十六进制颜色值的正则表达式
    var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
    /*RGB颜色转换为16进制*/
    String.prototype.toHexColor = function () {
        var that = this;
        if (/^(rgb|RGB)/.test(that)) {
            var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
            var strHex = "#";
            for (var i = 0; i < aColor.length; i++) {
                var hex = Number(aColor[i]).toString(16);
                if (hex.length === 1) {
                    hex = "0" + hex;
                }
                if (hex === "0") {
                    hex += hex;
                }
                strHex += hex;
            }
            if (strHex.length !== 7) {
                strHex = that;
            }
            return strHex.toUpperCase();
        } else if (reg.test(that)) {
            var aNum = that.replace(/#/, "").split("");
            if (aNum.length === 6) {
                return that.toUpperCase();
            } else if (aNum.length === 3) {
                var numHex = "#";
                for (var j = 0; j < aNum.length; j += 1) {
                    numHex += (aNum[j] + aNum[j]);
                }
                return numHex.toUpperCase();
            }
        } else {
            return that.toUpperCase();
        }
    };
    //-------------------------------------------------
    /*16进制颜色转为RGB格式*/
    String.prototype.toRgbColor = function () {
        var sColor = this.toLowerCase();
        if (sColor && reg.test(sColor)) {
            if (sColor.length === 4) {
                var sColorNew = "#";
                for (var i = 1; i < 4; i += 1) {
                    sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1));
                }
                sColor = sColorNew;
            }
            //处理六位的颜色值
            var sColorChange = [];
            for (var j = 1; j < 7; j += 2) {
                sColorChange.push(parseInt("0x" + sColor.slice(j, j + 2)));
            }
            return "RGB(" + sColorChange.join(",") + ")";
        } else {
            return sColor.toUpperCase();
        }
    };
    Array.prototype.unique = function () {
        this.sort();
        var re = [this[0]];
        for (var i = 1; i < this.length; i++) {
            if (this[i] !== re[re.length - 1]) {
                re.push(this[i]);
            }
        }
        return re;
    };
    Date.prototype.format = function (format) {
        var date = {
            "M+": this.getMonth() + 1,
            "d+": this.getDate(),
            "h+": this.getHours(),
            "m+": this.getMinutes(),
            "s+": this.getSeconds(),
            "q+": Math.floor((this.getMonth() + 3) / 3),
            "S+": this.getMilliseconds()
        };
        if (/(y+)/i.test(format)) {
            format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
        }
        for (var k in date) {
            if (new RegExp("(" + k + ")").test(format)) {
                format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? date[k] : ("00" + date[k]).substr(("" + date[k]).length));
            }
        }
        return format;
    };
    String.prototype.trim = function () {
        return this.replace(/(^\s*)|(\s*$)/g, "");
    };
    String.prototype.leftTrim = function () {
        return this.replace(/(^\s*)/g, "");
    };
    String.prototype.rightTrim = function () {
        return this.replace(/(\s*$)/g, "");
    };
    /**HashTable**/
    function HashTable() {
        this.size = 0;
        this.entry = {};
        var i, len, attr;
        if (typeof this.add !== 'function') {
            HashTable.prototype.add = function (key, value) {
                if (!this.containsKey(key)) {
                    this.size++;
                }
                this.entry[key] = value;
            };
        }
        if (typeof this.getValue !== 'function') {
            HashTable.prototype.getValue = function (key) {
                return this.containsKey(key) ? this.entry[key] : null;
            };
        }
        if (typeof this.remove !== 'function') {
            HashTable.prototype.remove = function (key) {
                if (this.containsKey(key) && (delete this.entry[key])) {
                    this.size--;
                }
            };
        }
        if (typeof this.containsKey !== 'function') {
            HashTable.prototype.containsKey = function (key) {
                return (key in this.entry);
            };
        }
        if (typeof this.containsValue !== 'function') {
            HashTable.prototype.containsValue = function (value) {
                var pkeys = Object.keys(this.entry);
                for (i = 0, len = pkeys.length; i < len; ++i) {
                    attr = pkeys[i];
                    if (this.entry[attr] === value) {
                        return true;
                    }
                }
                return false;
            };
        }
        if (typeof this.getValues !== 'function') {
            HashTable.prototype.getValues = function () {
                var values = [];
                var pkeys = Object.keys(this.entry);
                for (i = 0, len = pkeys.length; i < len; ++i) {
                    attr = pkeys[i];
                    values.push(this.entry[attr]);
                }
                return values;
            };
        }
        if (typeof this.getKeys !== 'function') {
            HashTable.prototype.getKeys = function () {
                var keys = Object.keys(this.entry);
                return keys;
            };
        }
        if (typeof this.getSize !== 'function') {
            HashTable.prototype.getSize = function () {
                return this.size;
            };
        }
        if (typeof this.clear !== 'function') {
            HashTable.prototype.clear = function () {
                this.size = 0;
                this.entry = {};
            };
        }
        if (typeof this.joinValue !== 'function') {
            HashTable.prototype.joinValue = function (key, value, split) {
                var sp = typeof split === 'undefined' ? ',' : split;
                var existValue = this.getValue(key);
                if (existValue === null) {
                    this.add(key, value);
                    this.size++;
                } else {
                    var arr = existValue.split(sp);
                    arr.push(value);
                    this.add(key, arr.join(sp));
                }
            };
        }
        if (typeof this.destroy !== 'function') {
            HashTable.prototype.destroy = function () {
                this.size = 0;
                this.entry = null;
            };
        }
        if (typeof this.each !== 'function') {
            HashTable.prototype.each = function (fn) {
                var pkeys = Object.keys(this.entry);
                for (i = 0, len = pkeys.length; i < len; ++i) {
                    attr = pkeys[i];
                    fn(attr, this.entry[attr]);
                }
            };
        }
        if (typeof this.getJson !== 'function') {
            HashTable.prototype.getJson = function (fn) {
                return $.extend(true, {}, this.entry);
            };
        }
    }
    $B["HashTable"] = HashTable;

    /**静态API**/
    $.extend($B, {
        /**框架的ajax统一入口
         *所有ajax返回均以 res={code:'',message:'',data:{}}的格式返回
        *code=0表示服务器无异常运行并返回结果，code=1时，表示服务器出现异常并返回提示
        *message，用与服务器返回的信息提示
        *data,用于服务器返回的数据，如tree组件、datagrid组件返回的数据就保存到data当中
        args={
                waiting:false ,     //是否显示waiting
                timeout: 1000 * 60, //超时
                type: "POST",       //请求方式
                dataType: 'json',   //请求数据类型
                async: true,        //是否异步
                preRequest: fn,     //请求前，回调
                url:'',             //请求url
                data:{},            //请求参数
                ok:function(message,data){},    //成功回调，message:返回信息，data:返回数据
                fail:function(message){},       //失败回调，message:返回信息
                final:function(res){}           //无论成功/失败都调用的回调 res = {code:'',message:'',data:{}}
        }
        ****/
        request: function () {
            var args = arguments[0];
            var opts;
            if (args !== undefined) {
                opts = $.extend({}, ajaxOpts, args);
            } else {
                opts = ajaxOpts;
            }
            if (typeof opts.preRequest === 'function') {
                opts.preRequest();
            }
            //剔除值为null的参数，null表示不需要更新到数据库
            for (var prop in opts.data) {
                if (opts.data[prop] === null) {
                    delete opts.data[prop];
                } else {
                    if(opts.notEncode){
                        opts.data[prop] = opts.data[prop];
                    }else{
                        opts.data[prop] = this.htmlEncode(opts.data[prop]);
                    }
                }
            }
            var queue = window["_submit_queues"];
            var submitBtn;
            if (queue && queue.length > 0) {
                var lastIdx = queue.length - 1;
                var diff = queue[lastIdx].date - new Date();
                if (diff <= 500) {//500毫秒内
                    submitBtn = queue[lastIdx].btn;
                    var q = queue.shift();
                    q.btn = undefined;
                }
            }
            if (arguments.length > 1  || submitBtn) {
                var btn = arguments.length > 1 ? arguments[1] : submitBtn;
                opts["target"] = btn;
                btn.attr("disabled", "disabled");
                if (btn[0].tagName === "INPUT") {
                    opts["recoverText"] = btn.val();
                    btn.val(config.busy);
                } else {
                    opts["recoverText"] = btn.html();
                    btn.html(config.busy);
                    var color = btn.css("color");
                    btn.prepend("<i style='padding:0;margin-right:3px;color:"+color+";' class='fa fa-spin6 animate-spin'></i>");
                }
            }
            if(opts.waiting){
                var $w = $B.busyTip({});
                opts.waitingObj = $w;
            }
            $.ajax(opts);
        },
        /***
         * 深色、浅色换转 
         * col 16进制颜色
         * amt自定义变暗参数，< 0为变暗，>0为变亮
         * ***/
        lightenDarkenColor: function (col, amt) {
            var usePound = false;
            if (col[0] === "#") {
                col = col.slice(1);
                usePound = true;
            }
            var num = parseInt(col, 16);
            var r = (num >> 16) + amt;
            if (r > 255) {
                r = 255;
            } else if (r < 0) {
                r = 0;
            }
            var b = ((num >> 8) & 0x00FF) + amt;
            if (b > 255) {
                b = 255;
            } else if (b < 0) {
                b = 0;
            }
            var g = (num & 0x0000FF) + amt;
            if (g > 255) {
                g = 255;
            } else if (g < 0) {
                g = 0;
            }
            return (usePound ? "#" : "") + String("000000" + (g | (b << 8) | (r << 16)).toString(16)).slice(-6);
        },
        /**
         * 判断颜色是否是浅色，深色
         * ***/
        isContrastYIQ: function (_color) {
            var colorrgb = _color;
            if (_color.indexOf("#") > -1) {
                colorrgb = _color.toRgbColor(); //colorRgb(hexcolor);
            }
            var colors = colorrgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
            var red = colors[1];
            var green = colors[2];
            var blue = colors[3];
            var brightness;
            brightness = (red * 299) + (green * 587) + (blue * 114);
            brightness = brightness / 255000;
            if (brightness >= 0.5) {
                return "light";
            } else {
                return "dark";
            }
        },
        /**
         * 用于提交期间，改变按钮的状态，防止重复提交
         * ***/
        changeButtonStatus: function (button) {
            var i = button.children("i");
            var clazz;
            if (button.attr("disabled")) {
                button.removeAttr("disabled");
                clazz = button.data("clazz");
                button.removeData("clazz").removeClass("k_toolbar_button_disabled");
                i.attr("class", clazz);
            } else {
                button.prop("disabled", true);
                clazz = i.attr("class");
                button.data("clazz", clazz).addClass("k_toolbar_button_disabled");
                i.attr("class", "fa fa-spin6 fa-spin");
            }
        },
        getHttpHost: function (ctxPath) {
            var proto = window.location.protocol;
            var host = proto + "//" + window.location.host;
            var ctx;
            if (!ctxPath && window.ctxPath) {
                ctx = window.ctxPath;
            } else if (ctxPath) {
                ctx = ctxPath;
            }
            if (ctx) {
                host = host + ctx;
            }
            return host;
        },
        htmlEncode: function (str) {
            if (!str || typeof str.replace === "undefined") {
                return str;
            }
            var s = "";
            if (str.length === 0) {
                return "";
            }
           // s = str.replace(/%/g,"%25");
            s = str.replace(/</g, "&lt;");
            s = s.replace(/>/g, "&gt;");
            s = s.replace(/eval\((.*)\)/g, "");
            s = s.replace(/<.*script.*>/, "");
            /*双引号 单引号不替换
            s = s.replace(/\'/g,"&#39;");
            s = s.replace(/\"/g,"&quot;");*/
            return s;
        },
        htmlDecode: function (str) {
            if (typeof str.replace === "undefined") {
                return str;
            }
            var s = "";
            if (str.length === 0) {
                return "";
            }
            s = str.replace(/&amp;/g, "&");
            s = s.replace(/&lt;/g, "<");
            s = s.replace(/&gt;/g, ">");
            s = s.replace(/&#39;/g, "\'");
            s = s.replace(/&quot;/g, "\"");
            return s;
        },        
        /**获取元素旋转后的位置偏移量**/
        getAnglePositionOffset: function (el) {
            var matrix = el.css("transform");
            var ofs = { fixTop: 0, fixLeft: 0 };
            if (matrix && matrix !== "none") {
                var pos = el.position();
                var angle = $B.getMatrixAngle(matrix);
                if (angle !== 0) {
                    var clone = $("<div />");
                    var style = el.attr("style");
                    clone.attr("style", style).css({ "filter": "alpha(opacity=0)", "-moz-opacity": "0", "opacity": "0", "position": "absolute", "z-index": -111 });
                    clone.css("transform", "rotate(0deg)");
                    clone.appendTo(el.parent());
                    var clonePos = clone.position();
                    ofs.fixTop = clonePos.top - pos.top;
                    ofs.fixLeft = -(pos.left - clonePos.left);
                    clone.remove();
                }
            }
            return ofs;
        },
        /**
         * 获取旋转的角度
         * matrix = css("transform")
         * **/
        getMatrixAngle: function (matrix) {
            if (matrix === "none") {
                return 0;
            }
            var values = matrix.split('(')[1].split(')')[0].split(',');
            var a = values[0];
            var b = values[1];
            var angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
            return angle;
        },
        /**
         * debug日志
         * ***/
        debug: function (message) {
            console.log("debug:" + message);
        },
        /**
         * 继承实现，child子类，parent父类，parent不传则默认为baseControl
         * _this 子类this, 
         * child 子类构造函数, 
         * parent 需要继承的父类构造函数,
         * args 参数
         * ****/
        extend: function (_this, child, parent, args) {
            if (!parent) {
                parent = BaseControl;
            }
            /***私有继承***/
            parent.call(_this, args);
            /***拷贝prototype继承***/
            Object.keys(parent.prototype).forEach(function (key) {
                var prop = child.prototype[key];
                if (!prop) { //如果子类已经存在，则不继承,模拟重写
                    child.prototype[key] = parent.prototype[key];
                }
            });
            child.prototype.constructor = child;
            //开放子类调用基类
            _this["super"] = new parent();
        },
        scrollbar: function (_this) {
            if (_this.mCustomScrollbar) {

            } else {
                _this.css("overflow", "auto");
            }
        },
        /**获取一个HashTable**/
        getHashTable: function () {
            return new HashTable();
        },
        /**是否是url**/
        isUrl: function (str) {
            if(typeof str !== 'string'){
                return false;
            }
            if(str && str.indexOf("/") < 0){
                return false;
            }
            return /^((http(s)?|ftp):\/\/)?([\w-]+\.)*[\w-]+(\/[\w-.\/?%&=]*)?(:\d+)?/.test(str);
        },
        /***
         * 写cookie
         * ***/
        writeCookie: function (name, value, expiredays) {
            if (!this.isNotEmpty(expiredays)) {
                expiredays = 1;
            }
            try {
                var exdate = new Date();
                exdate.setDate(exdate.getDate() + expiredays);
                document.cookie = name + "=" + window.escape(value) + ";expires=" + exdate.toGMTString();
            } catch (ex) {
            }
        },
        /**
         * 读取cookie
         * ***/
        getCookie: function (c_name) {
            if (document.cookie.length > 0) {
                var c_start = document.cookie.indexOf(c_name + "=");
                if (c_start !== -1) {
                    c_start = c_start + c_name.length + 1;
                    var c_end = document.cookie.indexOf(";", c_start);
                    if (c_end === -1) {
                        c_end = document.cookie.length;
                    }
                    return window.unescape(document.cookie.substring(c_start, c_end));
                }
            }
            return "";
        },
        isIE: function () {
            var userAgent = navigator.userAgent.toLowerCase();
            return userAgent.indexOf("rv:11.0") > 0 || /msie/.test(userAgent);
        },
        isNotEmpty: function (v) {
            return v !== null && typeof v !== 'undefiend' && v !== "";
        },
        /**获取滚动条宽度**/
        getScrollWidth: function () {
            var key = '_CURRENT_SCROLL_SIZE_';
            if( typeof window[key] !== "undefined"){
                return window[key];
            }
            var noScroll, scroll, oDiv = document.createElement("DIV");
            oDiv.style.cssText = "position:absolute; top:-1000px; width:100px; height:100px; overflow:hidden;";
            noScroll = document.body.appendChild(oDiv).clientWidth;
            oDiv.style.overflowY = "scroll";
            scroll = oDiv.clientWidth;
            document.body.removeChild(oDiv);
            window[key] = noScroll - scroll;
            return window[key] ;
        },
        /***
         * 创建高性能的延时运行函数（避免频繁执行）
         * func:需要延时运行的函数
         * wait:等待时间 毫秒
         * immediate:是否立即执行
         * 返回一个执行函数
         * ***/
        delayFun: function (func, wait, immediate) {
            var timeout;
            return function () {
                var context = this,
                    args = arguments;
                var later = function () {
                    timeout = null;
                    if (!immediate) {
                        func.apply(context, args);
                    }
                };
                var callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) {
                    func.apply(context, args);
                }
            };
        },
        /***
         * 对一个tag标签定义一个信息提示框
         * target:目标标签
         * message:提示的信息
         * timeout:自动消失时间，可以不填
         * return 返回提示框对象本身，可以需要关闭可以用 returnObj.hide() / returnObj.show() /returnObj.remove()
         * ***/
        tagMessage: function (target, message, timeout) { },
        /**
         * 获取当前url中参数，并以对象形式返回
         * @param strUrl 需要获取的url，如果不传则为当前打开页面的url
         * ***/
        getUrlParams: function (strUrl) {
            var url;
            if (strUrl !== undefined) {
                url = strUrl;
            } else {
                url = location.search;
            }
            var params = {};
            var index = url.indexOf("?");
            if (index !== -1) {
                var str = url.substr(index + 1);
                var strs = str.split("&");
                for (var i = 0; i < strs.length; i++) {
                    params[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
                }

            }
            /** 
            var obj = {};            
            var params = window.location.search.substr(1);
            //[^&=]+ 表示不含&或=的连续字符，加上()就是提取对应字符串
            url.replace(/([^&=]+)=([^&=]*)/gi,function(rs,$1,$2){
                obj[$1] =  decodeURIComponent($2);
            });
            return obj;
            **/
            return params;
        },
        /***
         * 获取当前鼠标的位置
         ***/
        mouseCoords: function (ev) {
            if (ev.pageX || ev.pageY) {
                return {
                    x: ev.pageX,
                    y: ev.pageY
                };
            } else {
                return {
                    x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
                    y: ev.clientY + document.body.scrollTop - document.body.clientTop
                };
            }
        },
        getEllipsisChar: function (txt, fs, width, height) {
            if ($ellipsisCharDiv === null) {
                $ellipsisCharDiv = _getBody().children("#" + _ellipsis_char_id);
                if ($ellipsisCharDiv.length === 0) {
                    $ellipsisCharDiv = $("<div style='height:" + height + "px;width:" + width + "px;position:absolute;top:0;z-index:0;overflow:auto;top:-1000px;' id='" + _ellipsis_char_id + "'></div>").appendTo(_getBody());
                }
            }
            $ellipsisCharDiv.css("font-size", fs).html("");
            var len = txt.length,
                i = 0;
            var el = $ellipsisCharDiv[0];
            for (; i < len; i++) {
                el.innerHTML = txt.substr(0, i);
                if (el.scrollHeight > height) {
                    el.innerHTML = txt.substr(0, i - 2);
                    break;
                }
            }
            return el.innerHTML + "...";
        },
        /***
         *获取字符长度
         *@param text 文本
         *@param fs 文本的字体大小
         **/
        getCharWidth: function (text, fs) {
            if (typeof fs === 'undefined') {
                fs = $B.config.fontSize;
            }
            if (!$spen_CharWidth) {
                $spen_CharWidth = $(charSpan.replace(/{id}/, _char_id_)).appendTo(_getBody());
            }
            $spen_CharWidth.css({
                'font-size': fs
            });
            var w = 20;
            try {
                $spen_CharWidth.html(this.htmlEncode(text));
                w = $spen_CharWidth.outerWidth();
                setTimeout(function () {
                    $spen_CharWidth.html("");
                }, 1);
            } catch (ex) {
                this.error(ex);
            }
            return w;
        },
        getIfrId:function(){
           return _getBody().children("#_window_ifr_id_").text();
        },
        getUUID: function () {
            return this.generateDateUUID();
        },
        generateDateUUID: function (fmt, count) {
            var c = count ? count : 12;
            var formt = fmt ? fmt : "yyyyMMddhhmmss";
            var prex = (new Date()).format(formt);
            return prex + this.generateMixed(c);
        },
        /***产生混合随机数
         *@param n 位数 默认6
         ***/
        generateMixed: function (n) {
            var _n = n ? n : 6;
            var res = [];
            for (var i = 0; i < _n; i++) {
                var id = Math.ceil(Math.random() * 35);
                res.push(chars[id]);
            }
            return res.join("");
        },
        /*** 某个html标签加载远程html文件
         options={  target:jquery目标对象,
                    url:'远程地址',
                    params:{},//参数
                    preload:function(){.........} , //加载前处理事件
                    onLoaded:function(result){.........}  //加载后处理事件
        } ***/
        htmlLoad: function () {
            var opts = arguments[0];
            opts.target.children().remove();
            opts.target.html(loadingHtml);
            if (typeof opts.preload === 'function') {
                opts.preload.call(opts.target);
            }
            var url = opts.url;
            if (url.indexOf("?") > 0) {
                url = url + "&_c_1=" + this.generateMixed(5);
            } else {
                url = url + "?_c_1=" + this.generateMixed(5);
            }
            opts.target.load(url, opts.params, function (xmlReq, statu, error) {
                if (statu === 'error') {
                    if (xmlReq) {
                        var re = new RegExp("<body[^>]*>([\\s\\S]*)<\\/body>", "gi");
                        var res = re.exec(xmlReq);
                        if (res != null && res.length >= 2) {
                            opts.target.html(res[1]);
                        } else {
                            opts.target.html(xmlReq);
                        }
                    } else {
                        var addr = $B.getHttpHost();
                        if (addr.indexOf("file:") >= 0) {
                            opts.target.html($B.config.crossError);
                        } else {
                            opts.target.html($B.config.htmlLoadError);
                        }
                    }
                } else {
                    if (typeof opts.onLoaded === 'function') {
                        opts.onLoaded.call(opts.target);
                    }
                }
            });
        },
        /**获取jquery对象
         * idOrTag
         * ***/
        getJqObject: function (idOrTag) {
            if (typeof idOrTag === 'string') {
                return $(idOrTag);
            } else {
                return idOrTag;
            }
        },
        /**
         *将form表单转为json对象
         *@param form 表单的容器如div、table、form
         *@param entityJson 实体json
         ***/
        parseForm: function (form, entityJson) {
            var _this = this;
            var formWrap = this.getJqObject(form);
            function objectToKeyValuePair($obj, _hash) {
                var _key = $obj.attr("id");
                if (!_key) {
                    _key = $obj.attr("name");
                }
                if (_key !== undefined) {
                    var _val = $obj.val();
                    _hash.add(_key, _val);
                    return _key + '=' + _val; //返回值，如果需要的话
                } else {
                    return null;
                }
            }
            var allText = formWrap.find("input[type=text]");
            var allPwdText = formWrap.find("input[type=password]");
            var allAreatext = formWrap.find("textarea");
            var allRadio = formWrap.find("input[type=radio]");
            var allCheckbox = formWrap.find("input[type=checkbox]");
            var allSelect = formWrap.find("select");
            var allHidden = formWrap.find("input[type=hidden]");
            var allFileText = formWrap.find("input[type=file]");
            var hash = this.getHashTable();
            //所有隐藏域
            $.each(allHidden, function (idx, obj) {
                objectToKeyValuePair($(obj), hash);
            });
            //所有密码框
            $.each(allPwdText, function (idx, obj) {
                objectToKeyValuePair($(obj), hash);
            });
            //查找所有文本框
            $.each(allText, function (idx, obj) {
                objectToKeyValuePair($(obj), hash);
            });
            //查找所有文件框
            $.each(allFileText, function (idx, obj) {
                objectToKeyValuePair($(obj), hash);
            });
            //查找所有多行文本
            $.each(allAreatext, function (idx, obj) {
                objectToKeyValuePair($(obj), hash);
            });
            /*****Radio******/
            $.each(allRadio, function (idx, obj) {
                hash.add($(obj).attr("name"), null); //先加键，value设空
            });
            $.each(allRadio, function (idx, obj) {
                var $t = $(obj);
                if ($t.is(":checked")) {
                    hash.joinValue($t.attr("name"), $t.val()); //设置值
                }
            });
            /*****Checkbox存在多选情况******/
            if (allCheckbox.length > 0) {
                var tempData = {};
                $.each(allCheckbox, function (idx, obj) {
                    var $obj = $(obj);
                    var _n = $obj.attr("name");
                    if (!tempData[_n]) {
                        tempData[_n] = []; //先加键，value设空
                    }
                    if ($obj.is(":checked")) {
                        tempData[_n].push($obj.val());
                    }
                });
                for (var key in tempData) {
                    if (this.hasOwnProperty(key)) {
                        var _v = tempData[key].join(',');
                        if (_v !== '') {
                            hash.add(key, _v); //设置值
                        }
                    }
                }
            }
            //查找所有下拉列表
            $.each(allSelect, function (idx, obj) {
                var $t = $(obj);
                if ($t.attr("multiple") === true) {
                    var allvalue = [];
                    hash.add($t.attr("name"), ''); //先加键，value设空
                    var sels = $t.children("option[selected]");
                    $.each(sels, function (j, o) {
                        allvalue.push($(o).value);
                    });
                    hash.joinValue($t.attr("name"), allvalue.join(',')); //设置值
                } else {
                    objectToKeyValuePair($t, hash);
                }
            });
            var objJson = hash.getJson();
            hash.destroy();
            if (entityJson) {
                return $.extend(true, {}, entityJson, objJson);
            } else {
                return objJson;
            }
        },
        /***实现双向绑定的表单填充
         *@param form 待填充的表单，如table、form
         *@param dataObj 填充数据，JSON对象
         *@param onchangeFn 
         *@return:返回具有双向联动能力的数据对象
         ***/
        bindForm: function (form, dataObj, onchangeFn) {
            var copyData = dataObj;//$.extend(true,{},dataObj);
            var oldFiledMap = {};
            if ($B.Mvvm) {
                var allText = form.find("input[type=text]");
                var bindExpressFn = function ($tag, setExprssFn) {
                    var prop = $tag.attr("id");
                    if (!prop) {
                        prop = $tag.attr("name");
                    }
                    if (typeof dataObj[prop] !== "undefined") {
                        setExprssFn($tag, prop);
                    }
                    //处理新旧验证
                    if (prop.indexOf("old_") === 0) {
                        var srProp = prop.replace("old_", "");
                        var v = dataObj[srProp];
                        $tag.val(v);
                        oldFiledMap[prop] = v;
                    }
                };
                allText.each(function () {
                    var $txt = $(this);
                    bindExpressFn($txt, function ($tag, prop) {
                        if ($tag.hasClass("k_combox_input")) {//对combox进行默认支持
                            $tag.attr("watcher", "kcomboxWatcher").attr("express", "{{this.kcomboxExpress(this.data." + prop + ",el)}}");
                        } else if ($tag.hasClass("k_calendar_input")) {//2019-05-03对时间日期控件进行支持
                            $tag.attr("watcher", "kcalendarWatcher").attr("express", "{{this.kcalendarExpress(this.data." + prop + ",el)}}");
                        }else if($tag.hasClass("k_window_input")){ //   2019-05-14支持window选择输入框
                            $tag.attr("watcher", "kwindowInputWatcher").attr("express", "{{this.kwindowInputExpress(this.data." + prop + ",el)}}");
                        } else {
                            $tag.attr("value", "{{this.data." + prop + "}}");
                        }
                    });
                });
                var allPwdText = form.find("input[type=password]");
                allPwdText.each(function () {
                    var $txt = $(this);
                    bindExpressFn($txt, function ($tag, prop) {
                        $tag.attr("value", "{{this.data." + prop + "}}");
                    });
                });

                var allHidden = form.find("input[type=hidden]");
                allHidden.each(function () {
                    var $txt = $(this);
                    bindExpressFn($txt, function ($tag, prop) {
                        $tag.attr("value", "{{this.data." + prop + "}}");
                    });
                });

                var allAreatext = form.find("textarea");
                allAreatext.each(function () {
                    var $txt = $(this);
                    bindExpressFn($txt, function ($tag, prop) {
                        $tag.text("{{this.data." + prop + "}}");
                    });
                });
                var allRadio = form.find("input[type=radio]");
                allRadio.each(function () {
                    var r = $(this);
                    var name = r.attr("name");
                    var $label = r.parent();
                    if ($label.hasClass("k_radio_label") && typeof dataObj[name] !== "undefined") {
                        $label.attr("watcher", "kRadioWatcher").attr("express", "{{this.kRadioExpress(this.data." + name + ",el)}}");
                    }
                });

                var allCheckbox = form.find("input[type=checkbox]");
                allCheckbox.each(function () {
                    var r = $(this);
                    var name = r.attr("name");
                    var $label = r.parent();
                    if ($label.hasClass("k_checkbox_label") && typeof dataObj[name] !== "undefined") {
                        $label.attr("watcher", "kcheckBoxWatcher").attr("express", "{{this.kcheckBoxExpress(this.data." + name + ",el)}}");
                    }
                });

                var allSelect = form.find("select");
                allSelect.each(function () {
                    var $ele = $(this);
                    var id = $ele.attr("id");
                    if (dataObj[id]) {
                        var optsHtml = [];
                        $ele.children().each(function () {
                            var opt = $(this);
                            var v = opt.val();
                            var txt = opt.text();
                            var sle = "{{this.data." + id + " === '" + v + "' ? true:false}}";
                            var optHtml = '<option value="' + v + '" selected="' + sle + '">' + txt + '</option>';
                            optsHtml.push(optHtml);
                        });
                        $ele.html(optsHtml.join(""));
                    }
                });
                //var allFileText = form.find("input[type=file]");
                //树形控件支持
                form.find("ul.k_tree_root").each(function () {
                    bindExpressFn($(this), function ($tag, prop) {
                        $tag.attr("watcher", "ktreeWatcher").attr("express", "{{this.ktreeExpress(this.data." + prop + ",el)}}");
                    });
                });
                var vm = new $B.Mvvm({
                    el: form[0],
                    data: copyData,
                    onChanged: onchangeFn,
                    onGetJson: function (json) {
                        $.extend(json, oldFiledMap);
                    }
                });
                window["curMvvm"] = vm;
                return vm;
            }else{
                console.log("没有加载mvvm组件");
            }
        },
        /***
         * 构建只读表单
         * ****/
        makeReadForm:function($wrap,formJson,data){
            console.log(" makeReadForm >>>>>>>>>>>>>>>>>>>>>>");
            $wrap.children().remove();
            var maxCol = 2;
            var one,$el,$table,$tr,labelWidth = "25%",form,forms;
            function fixColspan($table){
                $table.children().each(function(){
                    var $tr = $(this);
                    var count = $tr.children().length;
                    var colspan = maxCol - count;
                    if(colspan > 0){
                        $tr.children().last().attr("colspan",count + 1);
                    }
                });               
            } 
            function makderFormItem(form,tdWidth){
                var ftype = form.ftype;
                var val;
                $tr.append('<td style="width:60px;text-align: right;padding:2px 12px 2px 2px;">' + form.title + '</td>').children("td").width(tdWidth);    
                if(ftype === "select" || ftype === "radio"|| ftype === "checkbox"){
                    var txt = [];
                    var strVal = data[form.filedName] + "";
                    var idVal = strVal.split(",");
                    var id;
                    for(var i = 0,len = idVal.length ; i < len ;++i){
                        id = idVal[i];
                        for(var k = 0 ,klen = form.data.length ;k < klen ;k++){
                            if((form.data[k].id + "") === id){
                                txt.push(form.data[k].text);
                            }
                        }
                    }
                    if(txt.length > 0){
                        txt = txt.join("，");
                    }else{
                        txt = txt.join("");
                    }
                    $tr.append("<td>"+txt+"</td>");
                }else if(ftype === "file"){
                    val = data[form.filedName];
                    if(typeof val === "undefined"){
                        val = "";
                    }
                    if(val !== ""){
                        val = $B.getHttpHost(window.ctxPath) + val;
                    }
                    $tr.append("<td>"+val+"</td>");
                }else {
                    val = data[form.filedName];
                    if(typeof val === "undefined"){
                        val = "";
                    }
                    $tr.append("<td>"+val+"</td>");
                }
                if(window.onMakerFormCallFn){//调用注册的回调
                    window.onMakerFormCallFn($tr,form,data);
                }
            }
            //非分组无gName模式
            if(typeof formJson[0].gName === "undefined" && typeof formJson[0].forms === "undefined"){
                formJson = [{
                    gName:'',
                    forms:formJson
                }];
            }
            for (var i = 0, len = formJson.length; i < len; ++i) {
                one = formJson[i];
                if (one.gName && one.gName !== "") {
                    $el = $('<h6 class="k_des_dy_form_h6" style="cursor: pointer;"><i style="padding-right:4px;" class="fa  fa-down-open-big"></i>' + one.gName + '</h6>');
                    $el.appendTo($wrap).click(this._dyFormHclick);
                    if(i > 0){
                        $el.css("border-top","1px solid #CCCCCC");
                    }
                }
                forms = one.forms;
                $table = $('<table style="width:100%;" class="form_table k_dy_form_table"></table>');  
                maxCol = 2;                                       
                for (var j = 0, jlen = forms.length; j < jlen; ++j) {
                    form = forms[j];
                    $tr = $("<tr/>").appendTo($table);
                    if($.isArray(form)){//如果是数组，一行多个表单，支持两个
                       for(var k = 0 ,klen = form.length ; k < klen ;++k){
                          makderFormItem(form[k],"25%");
                       }
                    }else{//单行 当一表单
                        makderFormItem(form,labelWidth);
                    }
                    if($tr.children().length > maxCol){
                        maxCol = $tr.children().length;
                    }
                }                
                fixColspan($table);
                $table.appendTo($wrap);
            }  
        },
        /***
         *将json对象填充到容器中，与bindForm有区别，fillView只是将内容填充到对应的区域
         *这里填充的是任意元素，常用于填充到详情显示页面
         *@param wrap 待填充的容器对象
         *@param dataObj 填充数据，JSON对象
         ***/
        fillView: function (wrap, dataObj) {
            for (var attr in dataObj) {
                if (this.hasOwnProperty(attr)) {
                    var value = dataObj[attr];
                    if (value === null || value === undefined) {
                        value = "";
                    }
                    var $html = wrap.find("#" + attr);
                    if ($html.length > 0) {
                        if ($html[0].tagName === 'INPUT') {
                            $html.value(value);
                        } else {
                            $html.text(value);
                        }
                    }
                }
            }
        },
        /***
         *重置表单
         *@param form 需要重置的表单元素外包对象
         *@param defData 重置表单时候的默认数据，如果某个元素没有传默认值，则为空
         *defData 可以不传
         ****/
        resetForm: function (form, defData) {
        },
        /**
        * 简单下拉列表（原生的select）
         options={
             target:id/对象,
             data:option数据项,
             idField:'option的value字段',	
             textField:'option显示的字段',	
             defaultVal:'选择的项目的值',	  	
             onchange:fn(选择的option) //选择触发函数事件
         }
        *****/
        simpalSelect: function (options) {
            var target;
            if (typeof options.target === 'string') {
                target = $(options.target);
            } else {
                target = options.target;
            }
            target.children().remove();
            var selectedIt = null;
            if (typeof options.promptMsg !== 'undefined') {
                if (typeof options.promptValue !== 'undefined') {
                    selectedIt = $("<option  value='" + options.promptValue + "'>" + options.promptMsg + "</option>").appendTo(target);
                } else {
                    selectedIt = $("<option  value=''>" + options.promptMsg + "</option>").appendTo(target);
                }
            } else {
                selectedIt = target;
            }
            if ($.isArray(options.data)) {
                $.each(options.data, function (i, o) {
                    var v = o[options.idField];
                    var isSelected = false;
                    if ($.isArray(options.selected)) {
                        $.each(options.selected, function (j, item) {
                            if (v === item) {
                                isSelected = true;
                            }
                        });
                    }
                    var it = null;
                    if (isSelected) {
                        it = $("<option value='" + v + "' selected='selected'>" + o[options.textField] + "</option>").appendTo(target);
                    } else {
                        it = $("<option value='" + v + "' >" + o[options.textField] + "</option>").appendTo(target);
                    }
                    it.data("data", o);
                    if (typeof options.defaultVal === 'string' || typeof options.defaultVal === 'number') {
                        if (options.defaultVal === v) {
                            selectedIt = it;
                        }
                    }
                });
            }
            selectedIt.attr('selected', 'selected');
            if (typeof options.onchange === 'function') {
                target.on('change', function () {
                    var opt = $(this).children("option:selected");
                    options.onchange($(opt));
                });
            }
        },
        /**
         * des加密 依赖于encrypt-min.js
         * ***/
        encryptData: function (message, key) {
            if (typeof window["CryptoJS"] === "undefined") {
                console.log("没有加载 》》 CryptoJS");
                return message;
            }
            if (!key) {
                key = window["SRCUUID"];
            }
            var keyHex = window["CryptoJS"].enc.Utf8.parse(key);
            var encrypted = window["CryptoJS"].DES.encrypt(message, keyHex, {
                mode: window["CryptoJS"].mode.ECB,
                padding: window["CryptoJS"].pad.Pkcs7
            });
            return encrypted.toString();
        },
        _toTreeJson:function(json,treeJson,deep,parentPath,onCreateFn){
            var _this = this;
            setTimeout(function(){
                var keys = Object.keys(json);
                var key,obj,treeObj,prop,props,propObj,i,len,j,jlen,node,id;
                for(i = 0 ,len = keys.length ; i < len ;++i){
                    key = keys[i];
                    obj = json[key];
                    id = '_j'+deep+i;
                    var path = parentPath.join("/")+"/"+key;
                    if (parentPath.length > 0) {
                        path = "/" + path;
                    }
                    var newPathArray = [];
                    for(var n = 0 ,nlen = parentPath.length ; n < nlen ;++n){
                        newPathArray.push(parentPath[n]);
                    }
                    newPathArray.push(key);
                    treeObj = {id:id,text:key,data:{path:path}};               
                    if($.isArray(obj)){
                        treeObj.children = [];
                        if(deep > 1){
                            treeObj.closed = true;
                        }
                        for(j = 0 ,jlen = obj.length ; j < jlen ; ++j ){
                            node =  {id:id + j,text:key+"["+j+"]",data:{path:path}};
                            treeObj.children.push(node);
                            propObj = obj[j];
                            if($.isPlainObject(propObj)){
                                node.children = [];
                                if(deep > 1){
                                    node.closed = true;
                                }
                                _this._toTreeJson(propObj,node.children,deep++,newPathArray,onCreateFn);
                            }else{
                                node.text = node.text + " : "+ propObj;
                            }
                        }
                    }else if($.isPlainObject(obj)){
                        treeObj.children = [];
                        if(deep > 1){
                            treeObj.closed = true;
                        }
                        _this._toTreeJson(obj,treeObj.children,deep++,newPathArray,onCreateFn);
                    }else{
                        treeObj.text = key +" : "+obj;
                    }
                    treeJson.push(treeObj);
                }
                if(typeof onCreateFn === "undefined"){
                    _this._createJsonTree();
                }else{
                    onCreateFn();
                }
            },0);           
        },
        /**
         * json-查询器
         * **/
        jsonViewer:function(json,args,onCopy){
            var root = $("<ul class='k_json_view_root'/>");
            var treeJson = [];
            this._toTreeJson(json,treeJson,1,[]);
            this.$jsonTreeUl = root;
            this.treeJson = treeJson;
            var _this = this;
            var winCxt = $("<div style='padding:6px 12px;'></div>");
            winCxt.append("<div><button class='k_icon_fff'><i class='fa fa-docs'></i>"+$B.config.copy+"</button></div>");
            this.copyContent = JSON.stringify(json);
            winCxt.find("button").click(function(e){
                var $txt = _this.$jsonTreeUl.next("textarea");
                if($txt.length > 0){
                    $txt.remove();
                    _this.$jsonTreeUl.show();
                    $(this).html("<i class='fa fa-docs'></i>"+$B.config.copy);
                }else{
                    $(this).html("<i class='fa fa-docs'></i>"+$B.config.recoverCopy);
                    _this.$jsonTreeUl.hide();
                    $("<textarea style='width:100%;height:100%'>"+_this.copyContent+"</textarea>").insertAfter(_this.$jsonTreeUl);
                }               
            });
            winCxt.append(root);
            var winOpts = $.extend({
                width:'70%',
                height:'80%',
                content:winCxt,
                onClose:function(){
                    _this.$jsonTreeUl.data("treeIns").destroy();
                    _this.$jsonTreeUl = undefined;
                    _this.treeJson = undefined;
                    _this.copyContent = undefined;
                }
            },args);
            this.window(winOpts); 
            this.$jsonTreeUl.html("<li>please waiting.....</li>");
        },
        _createJsonTree:function(){
            clearTimeout(this.jsonViewTimer);           
            var _this = this;
            if(_this.$jsonTreeUl){
                this.jsonViewTimer = setTimeout(function(){
                    new $B.Tree(_this.$jsonTreeUl, {
                        plainStyle:true,
                        checkbox: false,
                        data: _this.treeJson
                    });               
                    _this.treeJson = undefined;
                },300);  
            }    
        },
        /**
         * des解密  依赖于encrypt-min.js
         * ***/
        decryptData: function (message, key) {
            if (typeof window["CryptoJS"] === "undefined") {
                return message;
            }
            if (!key) {
                key = window["SRCUUID"];
            }
            var keyHex = window["CryptoJS"].enc.Utf8.parse(key);
            var decrypted = window["CryptoJS"].DES.decrypt({
                ciphertext: window["CryptoJS"].enc.Base64.parse(message)
            }, keyHex, {
                    mode: window["CryptoJS"].mode.ECB,
                    padding: window["CryptoJS"].pad.Pkcs7
                });
            return decrypted.toString(window["CryptoJS"].enc.Utf8);
        },
        getLoadingMask:function(){
            var mask = $("<div  style='position:absolute;z-index: 2147483645;top:0;left:0;width:100%;height:100%;display:block;'><div id='k_window_mask_bg' style='width:100%;height:100%;position:absolute;top:0;left:0;z-index: 2147483646;display:block'></div><div style='text-align:center;width:100%;height:20px;line-height:20px;position:absolute;top:0;left:0;z-index: 2147483647;background: #EEEEEE;'><i class='fa fa-spin5 animate-spin'></i><span style='padding-left:8px;'>正在处理...</span></div></div>");
            return mask;
        },
        _dyFormHclick: function () {
            var $h = $(this);
            var $i = $h.children("i");
            if ($i.hasClass("fa-down-open-big")) {
                $i.removeClass("fa-down-open-big").addClass("fa-right-open-big").css("padding-left","5px");
                $h.next().slideUp(200, function () {
                    $(this).hide();
                });
            } else {
                $i.removeClass("fa-right-open-big").addClass("fa-down-open-big").css("padding-left","0");
                $h.next().show().slideDown(200);
            }
        },
        _dyFormLoad: function (url, el, type,reqId,filedName,dataObj) {
            (function (r, e, t,id,filed,obj,me) {
                $B.request({
                    url: r,
                    ok: function (msg, datas) {
                        delete me.reqQ[id];
                        //obj.data = datas;
                        //console.log(t +" 数据加载完成 "+ JSON.stringify(datas));
                        var $l = e;
                        var $p = e.parent();
                        while($p[0].nodeName !== "TABLE"){
                            $p = $p.parent();
                        }
                        if($p.parent().length === 0){//当前表单已经被销毁
                            return;
                        }
                        var chkVals = [];
                        for(var i = 0 ,len = datas.length ; i < len ;++i){
                            if(datas[i].checked){
                                chkVals.push(datas[i].id);
                            }
                            switch(t){
                                case "select":
                                    if(datas[i].selected){
                                        chkVals.push(datas[i].id);
                                    }
                                    $l.append("<option value='"+datas[i].id+"'>"+datas[i].text+"</option>");
                                break;                          
                                case "radio":
                                    if(datas[i].checked){
                                        chkVals.push(datas[i].id);
                                    }
                                    $l.append('<label class="k_radio_label k_radio_anim"><input type="radio" name="'+filed+'" value="'+datas[i].id+'" /><i class="k_radio_i"></i>'+datas[i].text+'</label>');
                                break;
                                case "checkbox":
                                    if(datas[i].checked){
                                        chkVals.push(datas[i].id);
                                    }
                                    $l.append('<label class="k_checkbox_label k_checkbox_anim"><input type="checkbox" name="'+filed+'" value="'+datas[i].id+'" /><i class="k_checkbox_i"></i>'+datas[i].text+'</label>');
                                break;
                            }
                        }
                        if(chkVals.length > 0){
                            dataObj.defaultVal = chkVals.join(",");
                        }                                        
                    },
                    final:function(){
                        delete me.reqQ[id];
                    }
                });
            })(url, el, type,reqId,filedName,dataObj,this);
        },
        _dyInputWindowClick:function(){
            var $t = $(this);           
            var params = $t.data("params");
            var filedName = params.filedName;
            var url = params.url;
            if(window.ctxPath){
				url = window.ctxPath + url;
			}else if(window.top.ctxPath){
				url = window.top.ctxPath + url;
			}
            if(url.indexOf("?") > 0){
                url = url + "&filed="+filedName;
            }else{
                url = url + "?filed="+filedName;
            }
            window["_curDyFiled"] = filedName; 
            var opts = {
                width:'60%',
                height:'70%',
                dataType:'html',
                title:params.title,
                url:url                
            };
            if (params.width) {
                opts.width = params.width;
            }
            if (params.height) {
                opts.height = params.height;
            }          
            window["_curDyWindow"] = $B.window(opts);
        },
        uploadDyFn:function($el,opts,propName,formData,dataListnerFn){           
            new $B.MutilUpload($.extend({
                target: $el,               
                timeout: 160, //160秒钟超时
                immediate: true, //选择文件后是否立即自动上传，即不用用户点击提交按钮就上传               
                success: function (res) { //成功时候的回调                   
                   dataListnerFn(formData, propName,res.data, "",res);                  
                },
                error: function (res) { //错误回调
                   console.log(res);
                   $B.error(res.message && res.message !== "" ? res.message : cfg.uploadException);
                }
            },opts));
        },
        clone:function(data){
            if($.isArray(data)){
                var tmp = [];
                for(var i = 0,len = data.length ; i < len ; ++i){
                    tmp.push($.extend(true,{},data[i]));
                }
                return tmp;
            }
            return $.extend(true,{},data);
        },
        /**
         * 动态表单
         * $wrap:容器
         * formJson：表单定义json
         * formData：表单对应的实体数据对象
         * labelWidth：标签td的宽度
         * **/
        dyForm: function ($wrap, formJson,formData,labelWidth,dataListnerFn) {           
            clearInterval(this._ivt);
            $wrap.children().each(function(){
                var $t = $(this);
                if(!$t.hasClass("k_dy_form_un_rm")){
                    $t.remove(); 
                }
            });
            var one, forms,form, $el, $table, $tr, 
                placeholder, data, filedName,attrs,reqId,
                 $tmpEl,m,mlen,opt,defaultValue,ftype;
            var inputWidth;
            if($wrap.width() <= 500){
                inputWidth = "99%";
            }
            var validateObj = {};//验证对象
            // var makeObj = false;
            // if($.isEmptyObject(formData)){//空的数据对象，则提前表单字段
            //     makeObj = true;
            // }
            var _this = this;
            window["_curDyDataObj"] = formData;
            this.reqQ = {};//用于检测远程请求数据是否完成 
            function makderFormItem(form,tdWidth){
                attrs = form.attrs;
                ftype = form.ftype;
                placeholder = form.tip ? form.tip : "";
                data = typeof form.data !== 'undefined' ? form.data : "";
                defaultValue = form.defaultValue;
                filedName = form.filedName;
                if(form.valid && form.valid !== ""){
                    validateObj[filedName] = form.valid;
                }
                var isUndefinedForm =  typeof formData[filedName] === "undefined";
                if(ftype === "file" || ftype === "label" || ftype === "hidden"  || ftype === "window" || ftype === "input" || ftype === "textarea" || ftype === "date"){
                    if(isUndefinedForm){
                        formData[filedName] = data;
                    }                  
                }else if(ftype === "select" || ftype === "radio" || ftype === "checkbox" || ftype === "combox" || ftype === "tree"){
                    if(isUndefinedForm){
                        if(typeof defaultValue !== "undefined"){
                            formData[filedName] = defaultValue;
                        }else{
                            formData[filedName] = "";
                        }
                    }
                }
                $tr.append('<td style="width:60px;text-align: right;padding:2px 12px 2px 2px;">' + form.title + '</td>').children("td").width(tdWidth);                   
                switch (form.ftype) {
                    case "label":
                        $tr.append('<td>'+data+'</td>');                             
                        break;
                    case "input":
                        $tr.append('<td><input type="text" id="'+filedName+'" title="'+placeholder+'" placeholder="'+placeholder+'" value="'+data+'"/></td>');
                        $tmpEl = $tr.find("input");
                        if(attrs){
                            $tmpEl.attr(attrs);
                        }
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }
                        break;
                    case "window": //  
                        $tmpEl = $tr.append('<td><input class="k_window_input"  title="'+placeholder+'" readonly="readonly" type="text" id="'+filedName+'"  placeholder="'+placeholder+'" value="'+data+'"/></td>').find("input");
                        var winOpt = {
                            filedName:filedName,
                            title:form.title
                        };
                        if (form.size) {
                            $.extend(winOpt, form.size);
                        }
                        if($B.isUrl(form.url)){
                            winOpt.url = form.url;
                        }
                        $tmpEl.click(_this._dyInputWindowClick).data("params",winOpt);    
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }    
                        if(attrs){
                            $tmpEl.attr(attrs);
                        }                   
                        break;
                    case "select":
                        $tmpEl = $('<td><select id="'+filedName+'"  title="'+placeholder+'" placeholder="'+placeholder+'"/></td>').appendTo($tr).children("select");
                        if($.isArray(data)){
                            for(m = 0 ,mlen = data.length ; m < mlen ; ++m){
                                $tmpEl.append("<option value='"+data[m].id+"'>"+data[m].text+"</option>");
                            }
                        }else{//url请求
                            reqId = $B.getUUID();
                            _this.reqQ[reqId] = true;
                            _this._dyFormLoad(data, $tmpEl, "select",reqId,filedName,form);
                        }     
                        if(attrs){
                            $tmpEl.attr(attrs);
                        }   
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }                    
                        break;
                    case "textarea":
                        $tr.append('<td><textarea  id="'+filedName+'"  title="'+placeholder+'"  placeholder="'+placeholder+'">'+data+'</textarea></td>');
                        $tmpEl =  $tr.find("textarea");
                        if(attrs){
                            $tmpEl.attr(attrs);
                        }   
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }
                        break;
                    case "radio":
                        $tmpEl = $('<td></td>').appendTo($tr);
                        if(typeof data === "string"){//url请求
                            reqId = $B.getUUID();
                            _this.reqQ[reqId] = true;
                            _this._dyFormLoad(data, $tmpEl, "radio",reqId,filedName,form);                         
                        }else{
                            delete data.unique;
                            for(m = 0 ,mlen = data.length ; m < mlen ; ++m){
                                $tmpEl.append('<label  title="'+placeholder+'" class="k_radio_label k_radio_anim"><input type="radio" name="'+filedName+'" value="'+data[m].id+'" /><i class="k_radio_i"></i>'+data[m].text+'</label>');
                            }
                        }
                        break;
                    case "checkbox":
                        $tmpEl = $('<td></td>').appendTo($tr);
                        if(typeof data === "string"){
                            reqId = $B.getUUID();
                            _this.reqQ[reqId] = true;
                            _this._dyFormLoad(data, $tmpEl, "checkbox",reqId,filedName,form);                            
                        }else{
                            delete data.unique;
                            for(m = 0 ,mlen = data.length ; m < mlen ; ++m){
                                $tmpEl.append('<label  title="'+placeholder+'" class="k_checkbox_label k_checkbox_anim"><input type="checkbox" name="'+filedName+'" value="'+data[m].id+'" /><i class="k_checkbox_i"></i>'+data[m].text+'</label>');
                            }
                        } 
                        break;
                    case "tree":
                        $tr.children("td").css("vertical-align","baseline"); //vertical-align: baseline;
                        $tmpEl = $tr.append('<td  title="'+placeholder+'"><ul id="'+filedName+'"/></td>').find("ul");                            
                        reqId = $B.getUUID();                            
                        (_this.treeDyFn)(form.mutilChecked,data,reqId,$tmpEl,form);
                        break;
                    case "combox":
                        $tmpEl = $tr.append('<td><input  title="'+placeholder+'" style="width: 99%;"  type="text" id="'+filedName+'"  placeholder="'+placeholder+'"/></td>').find("input");
                        reqId = $B.getUUID();  
                        (_this.comboxDyFn)(placeholder,form.mutilchecked,form.checkfather,form.readonly,data,reqId,$tmpEl);
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }
                        break;
                    case "date":
                        opt = {
                            fmt:form.fmt,
                            readonly:true
                        };
                        if(data === ""){
                            opt.initValue =  new Date();
                        }
                        $tmpEl = $tr.append('<td><input  title="'+placeholder+'" type="text" id="'+filedName+'"  placeholder="'+placeholder+'" value="'+data+'"/></td>').find("input"); 
                        new $B.Calendar($tmpEl,opt);
                        if(inputWidth){
                            $tmpEl.width(inputWidth);
                        }
                        break;
                    case "file":
                        $tmpEl = $tr.append('<td  title="'+placeholder+'"><div id="'+filedName+'"/></td>').find("div"); 
                        (_this.uploadDyFn)($tmpEl,form.opts,filedName,formData,dataListnerFn);
                        break;
                    case "time":
                        console.log("待完成....");
                        break;
                }
            }
            var maxCol = 2;
            function fixColspan($table){
                $table.children().each(function(){
                    var $tr = $(this);
                    var count = $tr.children().length;
                    var colspan = maxCol - count;
                    if(colspan > 0){
                        $tr.children().last().attr("colspan",count + 1);
                    }
                });               
            } 
            //非分组无gName模式
            if(typeof formJson[0].gName === "undefined" && typeof formJson[0].forms === "undefined"){
                formJson = [{
                    gName:'',
                    forms:formJson
                }];
            }
            for (var i = 0, len = formJson.length; i < len; ++i) {
                one = formJson[i];
                if (one.gName && one.gName !== "") {
                    $el = $('<h6 class="k_des_dy_form_h6" style="cursor: pointer;"><i style="padding-right:4px;" class="fa  fa-down-open-big"></i>' + one.gName + '</h6>');
                    $el.appendTo($wrap).click(this._dyFormHclick);
                    if(i > 0){
                        $el.css("border-top","1px solid #CCCCCC");
                    }
                }
                forms = one.forms;
                $table = $('<table style="width:100%;" class="form_table k_dy_form_table"></table>');  
                maxCol = 2;                                       
                for (var j = 0, jlen = forms.length; j < jlen; ++j) {
                    form = forms[j];
                    $tr = $("<tr/>").appendTo($table);
                    if($.isArray(form)){//如果是数组，一行多个表单，支持两个
                       for(var k = 0 ,klen = form.length ; k < klen ;++k){
                          makderFormItem(form[k],"25%");
                       }
                    }else{//单行 当一表单
                        makderFormItem(form,labelWidth);
                    }
                    if($tr.children().length > maxCol){
                        maxCol = $tr.children().length;
                    }
                }
                fixColspan($table);
                $table.appendTo($wrap);
            }            
            var count = 1;
            var loading;
            if(!$.isEmptyObject(_this.reqQ)){                
                loading = this.getLoadingMask();
                loading.appendTo($wrap);
            }
            if($wrap.data("min")){
                $wrap.children().hide();
            }
            _this._ivt = setInterval(function(){
                if(count > 5000){
                    clearInterval(_this._ivt);
                    $B.error($B.config.requestError);
                    if(loading){
                        loading.remove();
                    }
                }
                console.log("waiting for load the datas ....." + JSON.stringify(_this.reqQ));
                if($.isEmptyObject(_this.reqQ) ){
                    clearInterval(_this._ivt);
                    if(loading){
                        loading.remove();
                    }
                    if(!$.isEmptyObject(validateObj)){
                        new $B.Validate(validateObj,$wrap);
                     }
                     if(formData){//双休绑定实现
                       var mvmObj = $B.bindForm($wrap ,formData,dataListnerFn);
                       $wrap.data("mvmObj",mvmObj);
                     }
                }
                count++;
            },100);  
        },
        /**
         * 创建scroll
         * ***/
        makeNiceScroll:function(el,args){           
            el.css({"overflow":"hidden","position":"relative"});
            var wrap = $("<div class='k_box_size' style='margin-bottom: -17px; margin-right: -17px;overflow: scroll;height:100%;overflow-x:auto;'></div>").appendTo(el); 
            var scrollObj = new NiceScroll(wrap,args);        
            srcollArray.push(scrollObj);
            setTimeout(function(){
                scrollObj.updateUi();
            },500); 
            if(!SCROLLCHECKER){
                SCROLLCHECKER = setInterval(function(){
                    var tmpArray = [];
                    for(var i = 0 ,len = srcollArray.length ; i < len ;++i){
                        if( srcollArray[i].isLive()){                           
                            srcollArray[i].updateUi();
                            tmpArray.push(srcollArray[i]);
                        }
                    }
                    srcollArray = tmpArray;
                },700);
            }
            return wrap;
        },
        /***
         * pos 是否在 el元素内
         * pos = {top:,left}
         * el :jq元素
         * ***/
        isInElement:function(pos,el){
            var ofs =  el.offset();
            var w = el.outerWidth();
            var h = el.outerHeight();
            var endTop = ofs.top + h;
            var endLeft = ofs.left + w;
            if(pos.top >= ofs.top && pos.top <= endTop && pos.left >= ofs.left && pos.left <= endLeft){
                return true;
            }
            return false;
        }
    });
    $B.bindTextClear = function ($form) {
        var fn = function () {
            var $text = $(this);
            if (!$text.hasClass("k_combox_input")) {
                $text.on("mouseenter.textbox", TextEvents.mouseover);
                $text.on("input.textbox", TextEvents.input);
                $text.on("mouseleave.textbox", TextEvents.mouseout);
            }
        };
        $form.find("input[type=text]").each(fn);
        $form.find("input[type=password]").each(fn);
    };
    //往所有输入框加上清空按钮    
    $(function () {
        setTimeout(function () {
            $B.bindTextClear($("body"));
        }, 500);
    });
    window["$B"] = $B;

    /*********负值marin的滚动条***********/
    function NiceScroll(el,args){
        var opts = $.extend({              
                "border-radius": "6px",
                "position":"absolute",
                "width":"6px",
                "background":"#BCDBF7",
                opacity: 0.8
        },args);
      
        this.jqObj = el;
        this.vbar = $("<div style='top:0;right:1px;display:none;cursor:pointer;'></div>").css(opts).insertAfter(el);
        var _this = this;
        this.fireOnScroll = true;
        this.jqObj.on("scroll",function(){           
            if(_this.fireOnScroll){              
                _this.onScroll();
            }           
        });
        this.hideTimer = undefined;
        this.isDraging = false;
        this.jqObj.on({
            mouseenter:function(){ 
                if(!_this.isDraging){
                    _this.vbar.css("opacity","0.8");
                    _this.lastScrollHeight = 0;
                    _this.updateUi().show();
                }              
            },
            mouseleave:function(){   
               _this.hide();
            }
        });        
        this.vbar.on("mouseenter",function(){            
            _this.show();
            _this.vbar.css("opacity","1");
        }).on("mouseleave",function(){         
            _this.hide();           
        }).draggable({
            cursor:'pointer',
            axis: 'v', // v or h  水平还是垂直方向拖动 ，默认全向
            onStartDrag:function(args){               
                _this.maxTop = parseInt(_this.clientHeight - _this.vbar.height()) + 1;
                _this.fireOnScroll = false;
                _this.isDraging = true;
            },
            onDrag:function(args){
                var state = args.state;
                if(state._data.top < 0){
                    state._data.top = 0 ;
                }else if(state._data.top > _this.maxTop){
                    state._data.top = _this.maxTop;
                }
                var scrollPos = state._data.top / _this.scrollRate;
                _this.jqObj.scrollTop(scrollPos);
            },
            onStopDrag:function(){
                _this.fireOnScroll = true;
                _this.isDraging = false;
                return false;
            }
        });
        this.vbar.click(function(){           
            return false;
        });
    }
    NiceScroll.prototype = {
        onScroll:function(){
            if(this.vscrollSize <= 0){
                return;
            }
            if(this.vbar.css("display") === "none"){
                this.vbar.show();
            }
            var scrollTop = this.jqObj[0].scrollTop;
            this.posY = scrollTop  * this.scrollRate;
            this.vbar.css("top",this.posY);
        },
        show:function(){
            clearTimeout(this.hideTimer);
            this.vbar.show();
            return this;
        },
        hide:function(){
            var _this = this;
            if(this.isDraging){
                return this;
            }
            _this.hideTimer = setTimeout(function(){
                _this.vbar.hide(50);
            },800);
            return this;
        },
        /*****检查scroll容器是否还在dom文件中*******/
        isLive:function(){
            var p = this.jqObj.parent();
            var live = false;
            while(p.length > 0){
                if(p[0].tagName === "BODY"){
                    live = true;
                    break;
                }
                p = p.parent();
            }
            return live;
        },
        updateUi:function(){
            var wrap = this.jqObj[0];
            var scrollHeight = wrap.scrollHeight;
            var clientHeight = wrap.clientHeight;    
            var heightPercentage;  
            if( typeof this.lastScrollHeight !== 'undefined' && this.lastScrollHeight === scrollHeight){
                heightPercentage = (clientHeight * 100 / scrollHeight);  
                if(this.heightPercentage && heightPercentage === this.heightPercentage){
                    return this;
                }
            }
            this.lastScrollHeight = scrollHeight;           
            this.clientHeight = clientHeight;
            if(scrollHeight > 0){
                this.heightPercentage = heightPercentage;             
                var vbarHeigth = clientHeight * (this.heightPercentage / 100 );
                this.vscrollSize = Math.max(clientHeight, scrollHeight) - clientHeight; 
                if(this.vscrollSize > 0){
                    this.scrollRate =    (clientHeight - vbarHeigth) / this.vscrollSize; /***  bar移动一个像数，scroll移动 scrollRate 个像素****/ 
                    this.posY = wrap.scrollTop  * this.scrollRate;
                    this.vbar.css({"height":this.heightPercentage+"%","top": this.posY});
                }
            }else{
                this.vbar.hide();
            }      
            return this;
        }
    };
    var count = 0;
    var itv001 = setTimeout(function(){
        var $body = _getBody();
        if($body && $body.length > 0){
            clearInterval(itv001);
            if($body.children("#k_down_load_ifr").length === 0){
                var isLoadding = false;
                var ifr = $('<iframe  name="k_down_load_ifr" id="k_down_load_ifr" frameborder="0" style="display:none;vertical-align:top;" scroll="none" width="0" height="0" ></iframe>').appendTo($body );
                ifr.on("load",function(){         
                    if(isLoadding){
                        $B.error(config.file404,2);
                    }
                });
                setTimeout(function(){
                    isLoadding = true;
                },300);
            }
        }       
        count++;
        if(count > 20){
            clearInterval(itv001);
        }
    },100);
    return $B;
}));